<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>作用域-let-const块级作用域</title>
  <!-- 
  在JavaScript中， let  和  const  是 ES6 引入的用于声明变量的关键字，它们具有块级作用域的特性。
  1. 什么是块级作用域
  块级作用域是指变量的作用范围仅限于其被声明的代码块（用  {}  包裹的部分）。在块外部无法访问块内部声明的变量。这与  var  声明的变量不同， var  声明的变量是函数级作用域或全局作用域。

  2.  let  和  const  的块级作用域
   2.1  let  的块级作用域
  使用  let  声明的变量仅在其所在的块内有效。即使在同一函数中，不同的块也可以使用相同的变量名而不会发生冲突。
  {
      let x = 10;
      console.log(x); // 输出: 10
  }

  console.log(x); // 报错: x is not defined
  在上面的示例中，变量  x  只在其所在的块内有效，外部无法访问。

   2.2  const  的块级作用域
  const  声明的常量也具有块级作用域，且在声明时必须初始化，之后不可重新赋值。
  {
      const y = 20;
      console.log(y); // 输出: 20
  }

  console.log(y); // 报错: y is not defined
  同样，变量  y  也只在其块内有效，外部无法访问。

  3. 嵌套块级作用域
  在嵌套的块中，可以再次使用  let  和  const  声明相同名称的变量，而不会产生冲突。
  let a = 1;

  {
      let a = 2;
      console.log(a); // 输出: 2
  }

  console.log(a); // 输出: 1
  在这个例子中，外部的  a  和内部块的  a  是不同的变量。

  4. 作用域提升
  虽然  let  和  const  声明的变量会被提升，但它们不会被初始化，因此在声明之前访问这些变量会导致“暂时性死区”（Temporal Dead Zone）。
  // console.log(b); // 报错: Cannot access 'b' before initialization
  let b = 5;

  5. 总结
  - 块级作用域： let  和  const  声明的变量仅在其块内有效，外部无法访问。
  - 变量提升： let  和  const  变量会被提升，但在声明之前无法访问，导致暂时性死区。
  - 变量重复声明：在同一块内， let  和  const  不能重复声明，但可以在不同块中使用相同的变量名。
  - 最佳实践：使用  let  和  const  来提高代码的可读性和可维护性，避免全局变量污染和作用域混淆。
  -->
</head>
<body>

  <script>
    // 1. 在es5中，变量只有全局作用域和函数作用域，没有块级作用域
    // 代码块
    function fn() {
      console.log("es5", message);
    }
    {
      var message = "hello world";
    }
    console.log(message);
    fn()
    
    // 2. 在es6中，新增了块级作用域,使用let/const/function/class声明的变量是有块级作用域
    {
      let info = "hello world";
      console.log(info);

      class Person {}

      function fn() {
        console.log("es6", info);
      }
    }

    // console.log(info); // 报错: Cannot access 'info' before initialization
    // const p = new Person() // 报错: Cannot access 'Person' before initialization
    // fn() // 报错: Cannot access 'fn' before initialization
    

  </script>
  
</body>
</html>